@nice2dev/ui-3d 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/core/i18n.js +3 -3
- package/dist/cjs/dance/DanceBridge.js +13 -13
- package/dist/cjs/dance/DanceScoreEngine.js +8 -8
- package/dist/cjs/dance/PoseDetector.js +20 -20
- package/dist/cjs/material/NiceMaterialEditor.js +19 -19
- package/dist/cjs/model/ModelEditorLeftPanel.js +5 -5
- package/dist/cjs/model/ModelEditorMenuBar.js +6 -6
- package/dist/cjs/model/ModelEditorRightPanel.js +19 -19
- package/dist/cjs/model/ModelEditorSubComponents.js +10 -10
- package/dist/cjs/model/ModelEditorTimeline.js +6 -6
- package/dist/cjs/model/ModelEditorToolbar.js +4 -4
- package/dist/cjs/model/ModelEditorViewport.js +2 -2
- package/dist/cjs/model/ModelViewer.js +14 -14
- package/dist/cjs/model/NiceArmatureEditor.js +18 -18
- package/dist/cjs/model/NiceMorphTargetEditor.js +18 -18
- package/dist/cjs/model/NiceOctree.js +16 -16
- package/dist/cjs/model/NicePhysicsSimulation.js +24 -24
- package/dist/cjs/model/NiceProceduralGeometry.js +8 -8
- package/dist/cjs/model/NiceTerrainEditor.js +19 -19
- package/dist/cjs/model/NiceWeightPainter.js +14 -14
- package/dist/cjs/model/NiceXRPreview.js +18 -18
- package/dist/cjs/model/useModelEditor.js +127 -127
- package/dist/cjs/model/useModelViewer.js +61 -61
- package/dist/cjs/particle/NiceParticleEditor.js +11 -11
- package/dist/cjs/rendering/NiceCascadedShadows.js +12 -12
- package/dist/cjs/rendering/NiceRenderExport.js +5 -5
- package/dist/cjs/rendering/NiceSSAO.js +18 -18
- package/dist/cjs/rendering/NiceSSR.js +14 -14
- package/dist/cjs/rendering/NiceWebGPURenderer.js +21 -21
- package/dist/cjs/ui/dist/NiceButton-D9l39Rs7.js +598 -0
- package/dist/cjs/ui/dist/NiceButton-D9l39Rs7.js.map +1 -0
- package/dist/cjs/ui/dist/NiceErrorBoundary-niMx1aSJ.js +647 -0
- package/dist/cjs/ui/dist/NiceErrorBoundary-niMx1aSJ.js.map +1 -0
- package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-I_TXRiiY.js +5048 -0
- package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-I_TXRiiY.js.map +1 -0
- package/dist/cjs/ui/dist/NicePinCodeInput-CrMfdxxc.js +13081 -0
- package/dist/cjs/ui/dist/NicePinCodeInput-CrMfdxxc.js.map +1 -0
- package/dist/cjs/ui/dist/NiceSavedQueryPanel-CUAsdOjJ.js +6054 -0
- package/dist/cjs/ui/dist/NiceSavedQueryPanel-CUAsdOjJ.js.map +1 -0
- package/dist/cjs/ui/dist/NiceToggle-CaY1u82g.js +280 -0
- package/dist/cjs/ui/dist/NiceToggle-CaY1u82g.js.map +1 -0
- package/dist/cjs/ui/dist/NiceWindow-SiCaREbq.js +806 -0
- package/dist/cjs/ui/dist/NiceWindow-SiCaREbq.js.map +1 -0
- package/dist/cjs/ui/dist/charts-Bx_kNBsE.js +3508 -0
- package/dist/cjs/ui/dist/charts-Bx_kNBsE.js.map +1 -0
- package/dist/cjs/ui/dist/core-BpghV7Ls.js +10249 -0
- package/dist/cjs/ui/dist/core-BpghV7Ls.js.map +1 -0
- package/dist/cjs/ui/dist/index-CIl98Vbm.js +40039 -0
- package/dist/cjs/ui/dist/index-CIl98Vbm.js.map +1 -0
- package/dist/cjs/uv/NiceUVEditor.js +24 -24
- package/dist/esm/model/ModelEditorLeftPanel.js +4 -4
- package/dist/esm/model/ModelEditorMenuBar.js +4 -4
- package/dist/esm/model/ModelEditorRightPanel.js +5 -5
- package/dist/esm/model/ModelEditorSubComponents.js +2 -2
- package/dist/esm/model/ModelEditorTimeline.js +5 -5
- package/dist/esm/model/ModelEditorToolbar.js +3 -3
- package/dist/esm/model/ModelEditorViewport.js +2 -2
- package/dist/esm/model/ModelViewer.js +2 -2
- package/dist/esm/ui/dist/NiceButton-D9l39Rs7.js +593 -0
- package/dist/esm/ui/dist/NiceButton-D9l39Rs7.js.map +1 -0
- package/dist/esm/ui/dist/NiceErrorBoundary-niMx1aSJ.js +637 -0
- package/dist/esm/ui/dist/NiceErrorBoundary-niMx1aSJ.js.map +1 -0
- package/dist/esm/ui/dist/NiceModuleLifecyclePanel-I_TXRiiY.js +5007 -0
- package/dist/esm/ui/dist/NiceModuleLifecyclePanel-I_TXRiiY.js.map +1 -0
- package/dist/esm/ui/dist/NicePinCodeInput-CrMfdxxc.js +13011 -0
- package/dist/esm/ui/dist/NicePinCodeInput-CrMfdxxc.js.map +1 -0
- package/dist/esm/ui/dist/NiceSavedQueryPanel-CUAsdOjJ.js +6037 -0
- package/dist/esm/ui/dist/NiceSavedQueryPanel-CUAsdOjJ.js.map +1 -0
- package/dist/esm/ui/dist/NiceToggle-CaY1u82g.js +276 -0
- package/dist/esm/ui/dist/NiceToggle-CaY1u82g.js.map +1 -0
- package/dist/esm/ui/dist/NiceWindow-SiCaREbq.js +795 -0
- package/dist/esm/ui/dist/NiceWindow-SiCaREbq.js.map +1 -0
- package/dist/esm/ui/dist/charts-Bx_kNBsE.js +3483 -0
- package/dist/esm/ui/dist/charts-Bx_kNBsE.js.map +1 -0
- package/dist/esm/ui/dist/core-BpghV7Ls.js +10071 -0
- package/dist/esm/ui/dist/core-BpghV7Ls.js.map +1 -0
- package/dist/esm/ui/dist/index-CIl98Vbm.js +39917 -0
- package/dist/esm/ui/dist/index-CIl98Vbm.js.map +1 -0
- package/package.json +1 -1
package/dist/cjs/core/i18n.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
|
|
6
6
|
const fallback = (_key, defaultValue) => defaultValue;
|
|
7
|
-
const NiceI18nContext =
|
|
7
|
+
const NiceI18nContext = ke.createContext(fallback);
|
|
8
8
|
const NiceI18nProvider = ({ t, children }) => (jsxRuntime.jsx(NiceI18nContext.Provider, { value: t, children: children }));
|
|
9
9
|
function useNiceTranslation() {
|
|
10
|
-
const t =
|
|
10
|
+
const t = ke.useContext(NiceI18nContext);
|
|
11
11
|
return { t };
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var ke = require('react');
|
|
4
4
|
var DanceScoreEngine = require('./DanceScoreEngine.js');
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -113,13 +113,13 @@ class DanceBridge {
|
|
|
113
113
|
}
|
|
114
114
|
// ── React hook: useDanceBridge ──────────────────────────────────
|
|
115
115
|
function useDanceBridge(config, callbacks) {
|
|
116
|
-
const bridgeRef =
|
|
117
|
-
const [state, setState] =
|
|
118
|
-
const [lastScore, setLastScore] =
|
|
119
|
-
const [result, setResult] =
|
|
120
|
-
const [combo, setCombo] =
|
|
121
|
-
const [progress, setProgress] =
|
|
122
|
-
|
|
116
|
+
const bridgeRef = ke.useRef(null);
|
|
117
|
+
const [state, setState] = ke.useState('idle');
|
|
118
|
+
const [lastScore, setLastScore] = ke.useState(null);
|
|
119
|
+
const [result, setResult] = ke.useState(null);
|
|
120
|
+
const [combo, setCombo] = ke.useState(0);
|
|
121
|
+
const [progress, setProgress] = ke.useState(0);
|
|
122
|
+
ke.useEffect(() => {
|
|
123
123
|
if (!config) {
|
|
124
124
|
bridgeRef.current = null;
|
|
125
125
|
return;
|
|
@@ -134,11 +134,11 @@ function useDanceBridge(config, callbacks) {
|
|
|
134
134
|
return () => { bridgeRef.current = null; };
|
|
135
135
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
136
136
|
}, [config]);
|
|
137
|
-
const start =
|
|
138
|
-
const pause =
|
|
139
|
-
const resume =
|
|
140
|
-
const stop =
|
|
141
|
-
const feedFrame =
|
|
137
|
+
const start = ke.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.start(); }, []);
|
|
138
|
+
const pause = ke.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.pause(); }, []);
|
|
139
|
+
const resume = ke.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.resume(); }, []);
|
|
140
|
+
const stop = ke.useCallback(() => { var _a, _b; return (_b = (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.stop()) !== null && _b !== void 0 ? _b : null; }, []);
|
|
141
|
+
const feedFrame = ke.useCallback((frame) => {
|
|
142
142
|
var _a, _b;
|
|
143
143
|
const score = (_b = (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.feedFrame(frame)) !== null && _b !== void 0 ? _b : null;
|
|
144
144
|
if (bridgeRef.current)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var ke = require('react');
|
|
4
4
|
|
|
5
5
|
// ── Default config ──────────────────────────────────────────────
|
|
6
6
|
const DEFAULT_CONFIG = {
|
|
@@ -179,25 +179,25 @@ class DanceScoreEngine {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
function useDanceScore(config) {
|
|
182
|
-
const engineRef =
|
|
183
|
-
const [lastScore, setLastScore] =
|
|
184
|
-
const [result, setResult] =
|
|
185
|
-
const loadReference =
|
|
182
|
+
const engineRef = ke.useRef(new DanceScoreEngine(config));
|
|
183
|
+
const [lastScore, setLastScore] = ke.useState(null);
|
|
184
|
+
const [result, setResult] = ke.useState(null);
|
|
185
|
+
const loadReference = ke.useCallback((seq) => {
|
|
186
186
|
engineRef.current.loadReference(seq);
|
|
187
187
|
setLastScore(null);
|
|
188
188
|
setResult(null);
|
|
189
189
|
}, []);
|
|
190
|
-
const scoreFrame =
|
|
190
|
+
const scoreFrame = ke.useCallback((frame) => {
|
|
191
191
|
const score = engineRef.current.scoreFrame(frame);
|
|
192
192
|
setLastScore(score);
|
|
193
193
|
return score;
|
|
194
194
|
}, []);
|
|
195
|
-
const finish =
|
|
195
|
+
const finish = ke.useCallback(() => {
|
|
196
196
|
const r = engineRef.current.getResult();
|
|
197
197
|
setResult(r);
|
|
198
198
|
return r;
|
|
199
199
|
}, []);
|
|
200
|
-
const reset =
|
|
200
|
+
const reset = ke.useCallback(() => {
|
|
201
201
|
engineRef.current.reset();
|
|
202
202
|
setLastScore(null);
|
|
203
203
|
setResult(null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
|
|
6
6
|
// ── Standard keypoint definitions (COCO 17-keypoint model) ──────
|
|
7
7
|
const COCO_KEYPOINTS = [
|
|
@@ -31,14 +31,14 @@ function createSimulatedKeypoints() {
|
|
|
31
31
|
// ── Hook: usePoseDetection ──────────────────────────────────────
|
|
32
32
|
function usePoseDetection(config = {}) {
|
|
33
33
|
const { maxPersons = 1, minConfidence = 0.5, targetFps = 30, } = config;
|
|
34
|
-
const [isDetecting, setIsDetecting] =
|
|
35
|
-
const latestFrameRef =
|
|
36
|
-
const frameIndexRef =
|
|
37
|
-
const rafRef =
|
|
38
|
-
const streamRef =
|
|
39
|
-
const videoRef =
|
|
40
|
-
const callbackRef =
|
|
41
|
-
const processFrame =
|
|
34
|
+
const [isDetecting, setIsDetecting] = ke.useState(false);
|
|
35
|
+
const latestFrameRef = ke.useRef(null);
|
|
36
|
+
const frameIndexRef = ke.useRef(0);
|
|
37
|
+
const rafRef = ke.useRef(0);
|
|
38
|
+
const streamRef = ke.useRef(null);
|
|
39
|
+
const videoRef = ke.useRef(null);
|
|
40
|
+
const callbackRef = ke.useRef(null);
|
|
41
|
+
const processFrame = ke.useCallback(() => {
|
|
42
42
|
var _a;
|
|
43
43
|
if (!videoRef.current || videoRef.current.readyState < 2) {
|
|
44
44
|
rafRef.current = requestAnimationFrame(processFrame);
|
|
@@ -64,7 +64,7 @@ function usePoseDetection(config = {}) {
|
|
|
64
64
|
(_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, frame);
|
|
65
65
|
rafRef.current = requestAnimationFrame(processFrame);
|
|
66
66
|
}, [maxPersons, minConfidence, targetFps]);
|
|
67
|
-
const start =
|
|
67
|
+
const start = ke.useCallback(async (video, onFrame) => {
|
|
68
68
|
try {
|
|
69
69
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
70
70
|
video: { facingMode: 'user', width: { ideal: 640 }, height: { ideal: 480 } },
|
|
@@ -82,7 +82,7 @@ function usePoseDetection(config = {}) {
|
|
|
82
82
|
throw new Error(`Camera access failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
83
83
|
}
|
|
84
84
|
}, [processFrame]);
|
|
85
|
-
const stop =
|
|
85
|
+
const stop = ke.useCallback(() => {
|
|
86
86
|
var _a;
|
|
87
87
|
cancelAnimationFrame(rafRef.current);
|
|
88
88
|
(_a = streamRef.current) === null || _a === void 0 ? void 0 : _a.getTracks().forEach(t => t.stop());
|
|
@@ -91,22 +91,22 @@ function usePoseDetection(config = {}) {
|
|
|
91
91
|
videoRef.current.srcObject = null;
|
|
92
92
|
setIsDetecting(false);
|
|
93
93
|
}, []);
|
|
94
|
-
|
|
94
|
+
ke.useEffect(() => () => { stop(); }, [stop]);
|
|
95
95
|
return { start, stop, isDetecting, getLatestFrame: () => latestFrameRef.current };
|
|
96
96
|
}
|
|
97
97
|
// ── Component: PoseDetector ─────────────────────────────────────
|
|
98
|
-
const NicePoseDetector =
|
|
98
|
+
const NicePoseDetector = ke.forwardRef(function NicePoseDetector(props, ref) {
|
|
99
99
|
const { onFrame, onStart, onStop, onError, className, style, width = 640, height = 480, mirror = true, showSkeleton = true, showConfidence = false, ...config } = props;
|
|
100
|
-
const videoRef =
|
|
101
|
-
const canvasRef =
|
|
100
|
+
const videoRef = ke.useRef(null);
|
|
101
|
+
const canvasRef = ke.useRef(null);
|
|
102
102
|
const detection = usePoseDetection(config);
|
|
103
|
-
|
|
103
|
+
ke.useImperativeHandle(ref, () => ({
|
|
104
104
|
start: handleStart,
|
|
105
105
|
stop: handleStop,
|
|
106
106
|
getLatestFrame: detection.getLatestFrame,
|
|
107
107
|
get isDetecting() { return detection.isDetecting; },
|
|
108
108
|
}));
|
|
109
|
-
const drawSkeleton =
|
|
109
|
+
const drawSkeleton = ke.useCallback((frame) => {
|
|
110
110
|
var _a, _b, _c, _d, _e, _f;
|
|
111
111
|
const ctx = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getContext('2d');
|
|
112
112
|
if (!ctx || !canvasRef.current)
|
|
@@ -144,11 +144,11 @@ const NicePoseDetector = we.forwardRef(function NicePoseDetector(props, ref) {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
}, [showSkeleton, showConfidence]);
|
|
147
|
-
const handleFrame =
|
|
147
|
+
const handleFrame = ke.useCallback((frame) => {
|
|
148
148
|
drawSkeleton(frame);
|
|
149
149
|
onFrame === null || onFrame === void 0 ? void 0 : onFrame(frame);
|
|
150
150
|
}, [drawSkeleton, onFrame]);
|
|
151
|
-
const handleStart =
|
|
151
|
+
const handleStart = ke.useCallback(async () => {
|
|
152
152
|
try {
|
|
153
153
|
if (videoRef.current) {
|
|
154
154
|
await detection.start(videoRef.current, handleFrame);
|
|
@@ -159,7 +159,7 @@ const NicePoseDetector = we.forwardRef(function NicePoseDetector(props, ref) {
|
|
|
159
159
|
onError === null || onError === void 0 ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
160
160
|
}
|
|
161
161
|
}, [detection, handleFrame, onStart, onError]);
|
|
162
|
-
const handleStop =
|
|
162
|
+
const handleStop = ke.useCallback(() => {
|
|
163
163
|
detection.stop();
|
|
164
164
|
onStop === null || onStop === void 0 ? void 0 : onStop();
|
|
165
165
|
}, [detection, onStop]);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
var materialEditorTypes = require('./materialEditorTypes.js');
|
|
6
6
|
var materialNodeDefinitions = require('./materialNodeDefinitions.js');
|
|
7
7
|
var materialEditorUtils = require('./materialEditorUtils.js');
|
|
@@ -338,9 +338,9 @@ function materialEditorReducer(state, action) {
|
|
|
338
338
|
Hook: useMaterialEditor
|
|
339
339
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
340
340
|
function useMaterialEditor(initialGraph) {
|
|
341
|
-
const [state, dispatch] =
|
|
341
|
+
const [state, dispatch] = ke.useReducer(materialEditorReducer, initialGraph, createInitialState);
|
|
342
342
|
// Auto-compile when graph changes
|
|
343
|
-
|
|
343
|
+
ke.useEffect(() => {
|
|
344
344
|
if (state.autoCompile && !state.compiling) {
|
|
345
345
|
const timeout = setTimeout(() => {
|
|
346
346
|
dispatch({ type: 'COMPILE' });
|
|
@@ -356,7 +356,7 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
356
356
|
const filteredNodes = searchQuery
|
|
357
357
|
? materialNodeDefinitions.searchNodes(searchQuery)
|
|
358
358
|
: materialNodeDefinitions.MATERIAL_NODE_DEFINITIONS;
|
|
359
|
-
const categories =
|
|
359
|
+
const categories = ke.useMemo(() => {
|
|
360
360
|
const cats = new Map();
|
|
361
361
|
for (const node of filteredNodes) {
|
|
362
362
|
if (!cats.has(node.category)) {
|
|
@@ -369,9 +369,9 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
369
369
|
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.palette, children: [jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteSearch, children: jsxRuntime.jsx("input", { type: "text", placeholder: "Search nodes...", value: searchQuery, onChange: e => onSearch(e.target.value), className: MaterialEditor_module.searchInput }) }), jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteCategories, children: Array.from(categories.entries()).map(([category, nodes]) => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteCategory, children: [jsxRuntime.jsxs("button", { className: MaterialEditor_module.categoryHeader, onClick: () => onToggleCategory(category), style: { borderLeftColor: materialEditorTypes.NODE_CATEGORY_COLORS[category] }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryIcon, children: expandedCategories.includes(category) ? '▼' : '►' }), jsxRuntime.jsx("span", { children: materialEditorTypes.NODE_CATEGORY_NAMES[category] }), jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryCount, children: nodes.length })] }), expandedCategories.includes(category) && (jsxRuntime.jsx("div", { className: MaterialEditor_module.categoryNodes, children: nodes.map(nodeDef => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteNode, draggable: true, onDragStart: e => onDragStart(nodeDef.type, e), onDoubleClick: () => onAddNode(nodeDef.type), title: nodeDef.description, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeColor, style: { backgroundColor: nodeDef.color || materialEditorTypes.NODE_CATEGORY_COLORS[nodeDef.category] } }), jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
|
|
370
370
|
}
|
|
371
371
|
function GraphNode({ node, definition, selected, viewTransform, connections, onSelect, onMove, onStartConnection, }) {
|
|
372
|
-
const nodeRef =
|
|
373
|
-
const [isDragging, setIsDragging] =
|
|
374
|
-
const dragStart =
|
|
372
|
+
const nodeRef = ke.useRef(null);
|
|
373
|
+
const [isDragging, setIsDragging] = ke.useState(false);
|
|
374
|
+
const dragStart = ke.useRef(null);
|
|
375
375
|
const handleMouseDown = (e) => {
|
|
376
376
|
if (e.button !== 0)
|
|
377
377
|
return;
|
|
@@ -384,7 +384,7 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
|
|
|
384
384
|
dragStart.current = { x: e.clientX, y: e.clientY };
|
|
385
385
|
}
|
|
386
386
|
};
|
|
387
|
-
|
|
387
|
+
ke.useEffect(() => {
|
|
388
388
|
if (!isDragging)
|
|
389
389
|
return;
|
|
390
390
|
const handleMouseMove = (e) => {
|
|
@@ -441,10 +441,10 @@ function Toolbar({ canUndo, canRedo, canPaste, hasSelection, autoCompile, compil
|
|
|
441
441
|
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbar, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onNew, title: "New Material (Ctrl+N)", children: "\uD83D\uDCC4" }), jsxRuntime.jsx("button", { onClick: onImport, title: "Import (Ctrl+O)", children: "\uD83D\uDCC2" }), jsxRuntime.jsx("button", { onClick: onExport, title: "Export (Ctrl+S)", children: "\uD83D\uDCBE" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onUndo, disabled: !canUndo, title: "Undo (Ctrl+Z)", children: "\u21A9\uFE0F" }), jsxRuntime.jsx("button", { onClick: onRedo, disabled: !canRedo, title: "Redo (Ctrl+Y)", children: "\u21AA\uFE0F" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onCut, disabled: !hasSelection, title: "Cut (Ctrl+X)", children: "\u2702\uFE0F" }), jsxRuntime.jsx("button", { onClick: onCopy, disabled: !hasSelection, title: "Copy (Ctrl+C)", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("button", { onClick: onPaste, disabled: !canPaste, title: "Paste (Ctrl+V)", children: "\uD83D\uDCE5" }), jsxRuntime.jsx("button", { onClick: onDuplicate, disabled: !hasSelection, title: "Duplicate (Ctrl+D)", children: "\uD83D\uDD04" }), jsxRuntime.jsx("button", { onClick: onDelete, disabled: !hasSelection, title: "Delete (Del)", children: "\uD83D\uDDD1\uFE0F" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onSelectAll, title: "Select All (Ctrl+A)", children: "\u2B1C" }), jsxRuntime.jsx("button", { onClick: onZoomToFit, title: "Zoom to Fit (F)", children: "\uD83D\uDD0D" }), jsxRuntime.jsx("button", { onClick: onToggleGrid, className: showGrid ? MaterialEditor_module.active : '', title: "Toggle Grid (G)", children: "#" }), jsxRuntime.jsx("button", { onClick: onToggleSnap, className: snapToGrid ? MaterialEditor_module.active : '', title: "Toggle Snap (S)", children: "\uD83E\uDDF2" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onToggleAutoCompile, className: autoCompile ? MaterialEditor_module.active : '', title: "Auto Compile", children: "\u26A1" }), jsxRuntime.jsx("button", { onClick: onCompile, disabled: compiling, title: "Compile (F5)", children: compiling ? '⏳' : '▶️' })] })] }));
|
|
442
442
|
}
|
|
443
443
|
function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
444
|
-
const canvasRef =
|
|
444
|
+
const canvasRef = ke.useRef(null);
|
|
445
445
|
const previewModes = ['sphere', 'cube', 'plane', 'cylinder', 'torus'];
|
|
446
446
|
// Simple preview rendering (in real implementation would use Three.js)
|
|
447
|
-
|
|
447
|
+
ke.useEffect(() => {
|
|
448
448
|
const canvas = canvasRef.current;
|
|
449
449
|
if (!canvas)
|
|
450
450
|
return;
|
|
@@ -475,25 +475,25 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
|
475
475
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
476
476
|
function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, customNodes, textures, width = '100%', height = '600px', readOnly = false, showToolbar = true, showPalette = true, showProperties = true, showPreview = true, previewMode: initialPreviewMode = 'sphere', theme = 'dark', className, }) {
|
|
477
477
|
const { state, dispatch } = useMaterialEditor(initialGraph);
|
|
478
|
-
const canvasRef =
|
|
479
|
-
const [pendingConnection, setPendingConnection] =
|
|
478
|
+
const canvasRef = ke.useRef(null);
|
|
479
|
+
const [pendingConnection, setPendingConnection] = ke.useState(null);
|
|
480
480
|
// Merge custom node definitions
|
|
481
|
-
const definitions =
|
|
481
|
+
const definitions = ke.useMemo(() => {
|
|
482
482
|
const map = new Map(materialNodeDefinitions.MATERIAL_NODE_MAP);
|
|
483
483
|
customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach(def => map.set(def.type, def));
|
|
484
484
|
return map;
|
|
485
485
|
}, [customNodes]);
|
|
486
486
|
// Notify parent of changes
|
|
487
|
-
|
|
487
|
+
ke.useEffect(() => {
|
|
488
488
|
onGraphChange === null || onGraphChange === void 0 ? void 0 : onGraphChange(state.graph);
|
|
489
489
|
}, [state.graph, onGraphChange]);
|
|
490
|
-
|
|
490
|
+
ke.useEffect(() => {
|
|
491
491
|
if (state.compiledShader) {
|
|
492
492
|
onCompile === null || onCompile === void 0 ? void 0 : onCompile(state.compiledShader);
|
|
493
493
|
}
|
|
494
494
|
}, [state.compiledShader, onCompile]);
|
|
495
495
|
// Keyboard shortcuts
|
|
496
|
-
|
|
496
|
+
ke.useEffect(() => {
|
|
497
497
|
const handleKeyDown = (e) => {
|
|
498
498
|
if (readOnly)
|
|
499
499
|
return;
|
|
@@ -553,7 +553,7 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
553
553
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
554
554
|
}, [readOnly, state.selectedNodes, dispatch]);
|
|
555
555
|
// Handle wheel zoom
|
|
556
|
-
const handleWheel =
|
|
556
|
+
const handleWheel = ke.useCallback((e) => {
|
|
557
557
|
var _a;
|
|
558
558
|
e.preventDefault();
|
|
559
559
|
const delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
@@ -571,8 +571,8 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
571
571
|
});
|
|
572
572
|
}, [state.viewTransform, dispatch]);
|
|
573
573
|
// Handle canvas pan
|
|
574
|
-
const [isPanning, setIsPanning] =
|
|
575
|
-
const panStart =
|
|
574
|
+
const [isPanning, setIsPanning] = ke.useState(false);
|
|
575
|
+
const panStart = ke.useRef(null);
|
|
576
576
|
const handleCanvasMouseDown = (e) => {
|
|
577
577
|
if (e.button === 1 || (e.button === 0 && e.altKey)) {
|
|
578
578
|
setIsPanning(true);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
|
-
var
|
|
6
|
+
var NiceButtonD9l39Rs7 = require('../ui/dist/NiceButton-D9l39Rs7.js');
|
|
7
7
|
|
|
8
|
-
const ModelEditorLeftPanel =
|
|
8
|
+
const ModelEditorLeftPanel = ke.memo(({ api }) => {
|
|
9
9
|
const { sceneTree, selectedId, outlinerSearch, setOutlinerSearch, selectObject, rebuildTree, toggleNodeExpanded, toggleNodeVisibility, } = api;
|
|
10
10
|
const renderTreeNode = (node, depth) => {
|
|
11
11
|
// Outliner search filter
|
|
@@ -24,7 +24,7 @@ const ModelEditorLeftPanel = we.memo(({ api }) => {
|
|
|
24
24
|
node.type === "light" ? "💡" :
|
|
25
25
|
node.type === "camera" ? "📷" :
|
|
26
26
|
node.type === "helper" ? "◇" : "📁";
|
|
27
|
-
return (jsxRuntime.jsxs(
|
|
27
|
+
return (jsxRuntime.jsxs(ke.Fragment, { children: [jsxRuntime.jsxs("div", { className: `${ModelEditor_module.treeItem} ${selectedId === node.id ? ModelEditor_module.treeItemActive : ""}`, style: { paddingLeft: depth * 16 + 4 }, onClick: () => selectObject(node), children: [hasChildren ? (jsxRuntime.jsx("span", { className: ModelEditor_module.treeToggle, onClick: (e) => {
|
|
28
28
|
e.stopPropagation();
|
|
29
29
|
toggleNodeExpanded(node);
|
|
30
30
|
}, children: node.expanded ? "▼" : "▶" })) : (jsxRuntime.jsx("span", { className: ModelEditor_module.treeToggle })), jsxRuntime.jsx("span", { className: ModelEditor_module.treeIcon, children: icon }), jsxRuntime.jsx("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis" }, children: node.name }), jsxRuntime.jsx("span", { className: ModelEditor_module.treeVisibility, onClick: (e) => {
|
|
@@ -33,7 +33,7 @@ const ModelEditorLeftPanel = we.memo(({ api }) => {
|
|
|
33
33
|
}, children: node.visible ? "👁" : "◌" })] }), node.expanded &&
|
|
34
34
|
node.children.map((c) => renderTreeNode(c, depth + 1))] }, node.id));
|
|
35
35
|
};
|
|
36
|
-
return (jsxRuntime.jsx("div", { className: ModelEditor_module.leftPanel, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelTitle, children: ["\uD83D\uDCCB Outliner", jsxRuntime.jsx(
|
|
36
|
+
return (jsxRuntime.jsx("div", { className: ModelEditor_module.leftPanel, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelTitle, children: ["\uD83D\uDCCB Outliner", jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { variant: "ghost", size: "sm", onClick: rebuildTree, title: "Refresh", "aria-label": "Refresh outliner", children: "\u27F3" })] }), jsxRuntime.jsx("div", { className: ModelEditor_module.outlinerSearch, children: jsxRuntime.jsx(NiceButtonD9l39Rs7.b, { className: ModelEditor_module.propInput, placeholder: "\uD83D\uDD0D Filter...", value: outlinerSearch, onChange: (val) => setOutlinerSearch(val), style: { width: "100%", marginBottom: 4 } }) }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, style: { overflowY: "auto", flex: 1 }, children: [sceneTree.length === 0 && (jsxRuntime.jsx("div", { style: { color: "#666", fontSize: 10, padding: "8px 0" }, children: "Drop a 3D file to begin" })), sceneTree.map((n) => renderTreeNode(n, 0))] })] }) }));
|
|
37
37
|
});
|
|
38
38
|
ModelEditorLeftPanel.displayName = "ModelEditorLeftPanel";
|
|
39
39
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var NiceButtonD9l39Rs7 = require('../ui/dist/NiceButton-D9l39Rs7.js');
|
|
7
|
+
var NiceToggleCaY1u82g = require('../ui/dist/NiceToggle-CaY1u82g.js');
|
|
8
8
|
|
|
9
|
-
const ModelEditorMenuBar =
|
|
9
|
+
const ModelEditorMenuBar = ke.memo(({ api, hasOnSaveToLibrary }) => {
|
|
10
10
|
const { editorMode, setEditorMode, fileInputRef, mergeInputRef, addMenuOpen, setAddMenuOpen, addPrimitive, addSceneLight, addCameraObject, addEmpty, selectedNode, duplicateSelected, deleteSelected, exportGLTF, exportOBJ, exportSTL, exportPLY, exportUSDZ, saveToLibrary, clearScene, showGrid, setShowGrid, showAxes, setShowAxes, wireframe, setWireframe, showSkeleton, setShowSkeleton, showLightHelpers, setShowLightHelpers, bgColor, setBgColor, } = api;
|
|
11
|
-
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.menuBar, children: [jsxRuntime.jsx(
|
|
11
|
+
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.menuBar, children: [jsxRuntime.jsx(NiceButtonD9l39Rs7.a, { className: ModelEditor_module.modeSelect, value: editorMode, onChange: (val) => setEditorMode(val), options: [
|
|
12
12
|
{ value: "object", label: "Object Mode" },
|
|
13
13
|
{ value: "edit", label: "Edit Mode" },
|
|
14
14
|
{ value: "pose", label: "Pose Mode" },
|
|
15
|
-
] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(
|
|
15
|
+
] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: "\uD83D\uDCC2 Open" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => { var _a; return (_a = mergeInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, title: "Merge animations from FBX/GLTF onto current model", children: "\u2795 Merge Anim" }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs("div", { className: ModelEditor_module.menuDropdownWrap, children: [jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => setAddMenuOpen(addMenuOpen ? null : "mesh"), children: "\uFF0B Add \u25BE" }), addMenuOpen && (jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownMenu, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: "Mesh" }), ["cube", "sphere", "cylinder", "cone", "torus", "plane", "circle", "ring", "dodecahedron", "icosahedron", "octahedron", "tetrahedron", "torusKnot"].map((t) => (jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownItem, onClick: () => addPrimitive(t), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownSep }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: "Light" }), ["point", "spot", "directional", "hemisphere"].map((t) => (jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownItem, onClick: () => addSceneLight(t), children: ["\uD83D\uDCA1 ", t.charAt(0).toUpperCase() + t.slice(1)] }, t))), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownSep }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: "Other" }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownItem, onClick: addCameraObject, children: "\uD83D\uDCF7 Camera" }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownItem, onClick: () => addEmpty("arrows"), children: "\u22B9 Empty (Arrows)" })] }))] }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: duplicateSelected, disabled: !selectedNode, title: "Duplicate selected (Shift+D)", children: "\uD83D\uDCCB Duplicate" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: deleteSelected, disabled: !selectedNode, title: "Delete selected (Delete)", children: "\u2715 Delete" }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportGLTF(true), children: "\uD83D\uDCBE Export GLB" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportGLTF(false), children: "\uD83D\uDCC4 Export GLTF" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: exportOBJ, children: "\uD83D\uDCC4 Export OBJ" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportSTL(true), children: "\uD83D\uDCC4 Export STL" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportPLY(true), children: "\uD83D\uDCC4 Export PLY" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: exportUSDZ, children: "\uD83D\uDCC4 Export USDZ" }), hasOnSaveToLibrary && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: saveToLibrary, children: "\uD83D\uDCE6 Save to Library" })] })), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: clearScene, children: "\uD83D\uDDD1 Clear" }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showGrid, onChange: () => setShowGrid((v) => !v), label: "Grid" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showAxes, onChange: () => setShowAxes((v) => !v), label: "Axes" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: wireframe, onChange: () => setWireframe((v) => !v), label: "Wire" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showSkeleton, onChange: () => setShowSkeleton((v) => !v), label: "Skel" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showLightHelpers, onChange: () => setShowLightHelpers((v) => !v), label: "Helpers" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.menuRight, children: [jsxRuntime.jsx("label", { className: ModelEditor_module.menuLabel, children: "BG" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.N, { value: bgColor, onChange: (c) => setBgColor(c) })] })] }));
|
|
16
16
|
});
|
|
17
17
|
ModelEditorMenuBar.displayName = "ModelEditorMenuBar";
|
|
18
18
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var ke = require('react');
|
|
5
5
|
var THREE = require('three');
|
|
6
6
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
7
7
|
var modelEditorTypes = require('./modelEditorTypes.js');
|
|
8
8
|
var ModelEditorSubComponents = require('./ModelEditorSubComponents.js');
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
9
|
+
var NiceButtonD9l39Rs7 = require('../ui/dist/NiceButton-D9l39Rs7.js');
|
|
10
|
+
var NicePinCodeInputCrMfdxxc = require('../ui/dist/NicePinCodeInput-CrMfdxxc.js');
|
|
11
|
+
var NiceToggleCaY1u82g = require('../ui/dist/NiceToggle-CaY1u82g.js');
|
|
12
12
|
|
|
13
13
|
function _interopNamespaceDefault(e) {
|
|
14
14
|
var n = Object.create(null);
|
|
@@ -29,44 +29,44 @@ function _interopNamespaceDefault(e) {
|
|
|
29
29
|
|
|
30
30
|
var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
31
31
|
|
|
32
|
-
const ModelEditorRightPanel =
|
|
32
|
+
const ModelEditorRightPanel = ke.memo(({ api }) => {
|
|
33
33
|
const { propTab, setPropTab, selectedNode, selectedMaterials, selMaterialIdx, setSelMaterialIdx, setMatRefresh, rebuildTree, aiBusy, aiStatus, rootObjectRef, videoInputRef, bgColor, setBgColor, fogEnabled, setFogEnabled, fogColor, setFogColor, fogNear, setFogNear, fogFar, setFogFar, showLightHelpers, setShowLightHelpers, showGrid, setShowGrid, showAxes, setShowAxes, showSkeleton, setShowSkeleton, snapEnabled, setSnapEnabled, snapGrid, setSnapGrid, setStatusText, } = api;
|
|
34
|
-
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.rightPanel, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.propTabs, children: ["object", "material", "world", "modifiers", "physics"].map((t) => (jsxRuntime.jsx(
|
|
34
|
+
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.rightPanel, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.propTabs, children: ["object", "material", "world", "modifiers", "physics"].map((t) => (jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.propTabBtn, variant: propTab === t ? "primary" : "ghost", size: "sm", onClick: () => setPropTab(t), title: t.charAt(0).toUpperCase() + t.slice(1), children: t === "object" ? "🔧" : t === "material" ? "🎨" : t === "world" ? "🌍" : t === "modifiers" ? "🔩" : "⚡" }, t))) }), propTab === "object" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDD27 Transform" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: selectedNode ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Name" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.b, { className: ModelEditor_module.propInput, value: selectedNode.name, onChange: (val) => {
|
|
35
35
|
selectedNode.object.name = val;
|
|
36
36
|
rebuildTree();
|
|
37
|
-
} })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Type" }), jsxRuntime.jsx("span", { style: { fontSize: 10, color: "#888" }, children: selectedNode.type })] }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3Row, { label: "Position", value: selectedNode.object.position, onChange: () => setMatRefresh((n) => n + 1) }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3RowDeg, { label: "Rotation", value: selectedNode.object.rotation, onChange: () => setMatRefresh((n) => n + 1) }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3Row, { label: "Scale", value: selectedNode.object.scale, onChange: () => setMatRefresh((n) => n + 1) })] })) : (jsxRuntime.jsx("div", { style: { color: "#666", fontSize: 10 }, children: "Select an object" })) })] }), selectedNode && selectedNode.object instanceof THREE__namespace.Light && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDCA1 Light" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Color" }), jsxRuntime.jsx(
|
|
37
|
+
} })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Type" }), jsxRuntime.jsx("span", { style: { fontSize: 10, color: "#888" }, children: selectedNode.type })] }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3Row, { label: "Position", value: selectedNode.object.position, onChange: () => setMatRefresh((n) => n + 1) }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3RowDeg, { label: "Rotation", value: selectedNode.object.rotation, onChange: () => setMatRefresh((n) => n + 1) }), jsxRuntime.jsx(ModelEditorSubComponents.Vec3Row, { label: "Scale", value: selectedNode.object.scale, onChange: () => setMatRefresh((n) => n + 1) })] })) : (jsxRuntime.jsx("div", { style: { color: "#666", fontSize: 10 }, children: "Select an object" })) })] }), selectedNode && selectedNode.object instanceof THREE__namespace.Light && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDCA1 Light" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Color" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.N, { value: `#${selectedNode.object.color.getHexString()}`, onChange: (c) => {
|
|
38
38
|
selectedNode.object.color.set(c);
|
|
39
39
|
setMatRefresh((n) => n + 1);
|
|
40
|
-
} })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Intensity" }), jsxRuntime.jsx(
|
|
40
|
+
} })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Intensity" }), jsxRuntime.jsx(NicePinCodeInputCrMfdxxc.U, { min: 0, max: 10, step: 0.1, value: selectedNode.object.intensity, onChange: (val) => {
|
|
41
41
|
selectedNode.object.intensity = val;
|
|
42
42
|
setMatRefresh((n) => n + 1);
|
|
43
|
-
}, style: { flex: 1 } }), jsxRuntime.jsx("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: selectedNode.object.intensity.toFixed(1) })] }), "castShadow" in selectedNode.object && (jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Shadow" }), jsxRuntime.jsx(
|
|
43
|
+
}, style: { flex: 1 } }), jsxRuntime.jsx("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: selectedNode.object.intensity.toFixed(1) })] }), "castShadow" in selectedNode.object && (jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Shadow" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: selectedNode.object.castShadow, onChange: (checked) => {
|
|
44
44
|
selectedNode.object.castShadow = checked;
|
|
45
45
|
setMatRefresh((n) => n + 1);
|
|
46
|
-
} })] })), selectedNode.object instanceof THREE__namespace.SpotLight && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Angle" }), jsxRuntime.jsx(
|
|
46
|
+
} })] })), selectedNode.object instanceof THREE__namespace.SpotLight && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Angle" }), jsxRuntime.jsx(NicePinCodeInputCrMfdxxc.U, { min: 0, max: 90, step: 1, value: (selectedNode.object.angle * modelEditorTypes.DEG), onChange: (val) => {
|
|
47
47
|
selectedNode.object.angle = val / modelEditorTypes.DEG;
|
|
48
48
|
setMatRefresh((n) => n + 1);
|
|
49
|
-
}, style: { flex: 1 } }), jsxRuntime.jsxs("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: [(selectedNode.object.angle * modelEditorTypes.DEG).toFixed(0), "\u00B0"] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Penumbra" }), jsxRuntime.jsx(
|
|
49
|
+
}, style: { flex: 1 } }), jsxRuntime.jsxs("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: [(selectedNode.object.angle * modelEditorTypes.DEG).toFixed(0), "\u00B0"] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Penumbra" }), jsxRuntime.jsx(NicePinCodeInputCrMfdxxc.U, { min: 0, max: 1, step: 0.01, value: selectedNode.object.penumbra, onChange: (val) => {
|
|
50
50
|
selectedNode.object.penumbra = val;
|
|
51
51
|
setMatRefresh((n) => n + 1);
|
|
52
|
-
}, style: { flex: 1 } })] })] }))] })] })), selectedNode && selectedNode.object instanceof THREE__namespace.PerspectiveCamera && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDCF7 Camera" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "FOV" }), jsxRuntime.jsx(
|
|
52
|
+
}, style: { flex: 1 } })] })] }))] })] })), selectedNode && selectedNode.object instanceof THREE__namespace.PerspectiveCamera && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDCF7 Camera" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "FOV" }), jsxRuntime.jsx(NicePinCodeInputCrMfdxxc.U, { min: 10, max: 120, step: 1, value: selectedNode.object.fov, onChange: (val) => {
|
|
53
53
|
const cam = selectedNode.object;
|
|
54
54
|
cam.fov = val;
|
|
55
55
|
cam.updateProjectionMatrix();
|
|
56
56
|
setMatRefresh((n) => n + 1);
|
|
57
|
-
}, style: { flex: 1 } }), jsxRuntime.jsxs("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: [selectedNode.object.fov.toFixed(0), "\u00B0"] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Near" }), jsxRuntime.jsx(
|
|
57
|
+
}, style: { flex: 1 } }), jsxRuntime.jsxs("span", { style: { fontSize: 9, color: "#888", width: 28, textAlign: "right" }, children: [selectedNode.object.fov.toFixed(0), "\u00B0"] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Near" }), jsxRuntime.jsx(NiceToggleCaY1u82g.a, { className: ModelEditor_module.propInput, step: 0.01, value: selectedNode.object.near, onChange: (val) => {
|
|
58
58
|
const cam = selectedNode.object;
|
|
59
59
|
cam.near = val !== null && val !== void 0 ? val : 0.1;
|
|
60
60
|
cam.updateProjectionMatrix();
|
|
61
61
|
setMatRefresh((n) => n + 1);
|
|
62
|
-
}, style: { width: 60 } })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Far" }), jsxRuntime.jsx(
|
|
62
|
+
}, style: { width: 60 } })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Far" }), jsxRuntime.jsx(NiceToggleCaY1u82g.a, { className: ModelEditor_module.propInput, step: 1, value: selectedNode.object.far, onChange: (val) => {
|
|
63
63
|
const cam = selectedNode.object;
|
|
64
64
|
cam.far = val !== null && val !== void 0 ? val : 1000;
|
|
65
65
|
cam.updateProjectionMatrix();
|
|
66
66
|
setMatRefresh((n) => n + 1);
|
|
67
|
-
}, style: { width: 80 } })] })] })] })), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83E\uDD16 AI Animation" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.aiPanel, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.aiHeader, children: "\u2728 Generate animation from video" }), jsxRuntime.jsx("p", { style: { fontSize: 10, color: "#888", margin: "0 0 6px" }, children: "Upload a video and AI will extract 3D pose data to create an animation clip for the current model." }), jsxRuntime.jsx("div", { className: ModelEditor_module.aiBtnRow, children: jsxRuntime.jsx(
|
|
67
|
+
}, style: { width: 80 } })] })] })] })), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83E\uDD16 AI Animation" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.aiPanel, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.aiHeader, children: "\u2728 Generate animation from video" }), jsxRuntime.jsx("p", { style: { fontSize: 10, color: "#888", margin: "0 0 6px" }, children: "Upload a video and AI will extract 3D pose data to create an animation clip for the current model." }), jsxRuntime.jsx("div", { className: ModelEditor_module.aiBtnRow, children: jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.aiBtn, variant: "ghost", size: "sm", disabled: aiBusy || !rootObjectRef.current, onClick: () => { var _a; return (_a = videoInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: aiBusy ? "Processing..." : "Upload Video" }) }), aiStatus && (jsxRuntime.jsx("div", { className: ModelEditor_module.aiStatus, children: aiStatus }))] }) })] })] })), propTab === "material" && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83C\uDFA8 Materials" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: selectedMaterials.length > 0 ? (selectedMaterials.map((mat, i) => (jsxRuntime.jsx(ModelEditorSubComponents.MaterialCard, { material: mat, active: i === selMaterialIdx, onClick: () => setSelMaterialIdx(i), onUpdate: () => setMatRefresh((n) => n + 1) }, i)))) : (jsxRuntime.jsx("div", { style: { color: "#666", fontSize: 10 }, children: selectedNode
|
|
68
68
|
? "No materials on this object"
|
|
69
|
-
: "Select a mesh to inspect" })) })] })), propTab === "world" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83C\uDF0D Environment" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Background" }), jsxRuntime.jsx(
|
|
69
|
+
: "Select a mesh to inspect" })) })] })), propTab === "world" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83C\uDF0D Environment" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Background" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.N, { value: bgColor, onChange: (c) => setBgColor(c) }), jsxRuntime.jsx("span", { style: { fontSize: 9, color: "#888" }, children: bgColor })] }) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83C\uDF2B Fog" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Enable" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: fogEnabled, onChange: () => setFogEnabled((v) => !v) })] }), fogEnabled && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Color" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.N, { value: fogColor, onChange: (c) => setFogColor(c) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Near" }), jsxRuntime.jsx(NiceToggleCaY1u82g.a, { className: ModelEditor_module.propInput, value: fogNear, onChange: (val) => setFogNear(val !== null && val !== void 0 ? val : 1), style: { width: 60 } })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Far" }), jsxRuntime.jsx(NiceToggleCaY1u82g.a, { className: ModelEditor_module.propInput, value: fogFar, onChange: (val) => setFogFar(val !== null && val !== void 0 ? val : 100), style: { width: 60 } })] })] }))] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDD06 Scene Lights" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Show Helpers" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showLightHelpers, onChange: () => setShowLightHelpers((v) => !v) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Grid" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showGrid, onChange: () => setShowGrid((v) => !v) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Axes" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showAxes, onChange: () => setShowAxes((v) => !v) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Skeleton" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: showSkeleton, onChange: () => setShowSkeleton((v) => !v) })] })] })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83E\uDDF2 Snapping" }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Snap" }), jsxRuntime.jsx(NiceToggleCaY1u82g.N, { checked: snapEnabled, onChange: () => setSnapEnabled((v) => !v) })] }), snapEnabled && (jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Grid Size" }), jsxRuntime.jsx(NiceToggleCaY1u82g.a, { className: ModelEditor_module.propInput, step: 0.25, min: 0.1, value: snapGrid, onChange: (val) => setSnapGrid(val !== null && val !== void 0 ? val : 1), style: { width: 60 } })] }))] })] })] })), propTab === "modifiers" && (jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDD29 Modifiers" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: selectedNode && selectedNode.object instanceof THREE__namespace.Mesh ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.btnSecondary, variant: "ghost", size: "sm", style: { width: "100%", marginBottom: 4 }, onClick: () => {
|
|
70
70
|
const mesh = selectedNode.object;
|
|
71
71
|
const geo = mesh.geometry;
|
|
72
72
|
const pos = geo.attributes.position;
|
|
@@ -76,17 +76,17 @@ const ModelEditorRightPanel = we.memo(({ api }) => {
|
|
|
76
76
|
setStatusText("Applied Wireframe modifier");
|
|
77
77
|
rebuildTree();
|
|
78
78
|
}
|
|
79
|
-
}, children: "+ Wireframe Modifier" }), jsxRuntime.jsx(
|
|
79
|
+
}, children: "+ Wireframe Modifier" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.btnSecondary, variant: "ghost", size: "sm", style: { width: "100%", marginBottom: 4 }, onClick: () => {
|
|
80
80
|
const mesh = selectedNode.object;
|
|
81
81
|
mesh.geometry.computeVertexNormals();
|
|
82
82
|
setStatusText("Recomputed normals");
|
|
83
|
-
}, children: "Recompute Normals" }), jsxRuntime.jsx(
|
|
83
|
+
}, children: "Recompute Normals" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.btnSecondary, variant: "ghost", size: "sm", style: { width: "100%", marginBottom: 4 }, onClick: () => {
|
|
84
84
|
const mesh = selectedNode.object;
|
|
85
85
|
const geo = mesh.geometry;
|
|
86
86
|
geo.center();
|
|
87
87
|
setStatusText("Centered geometry");
|
|
88
88
|
setMatRefresh((n) => n + 1);
|
|
89
|
-
}, children: "Center Geometry" }), jsxRuntime.jsx(
|
|
89
|
+
}, children: "Center Geometry" }), jsxRuntime.jsx(NiceButtonD9l39Rs7.c, { className: ModelEditor_module.btnSecondary, variant: "ghost", size: "sm", style: { width: "100%", marginBottom: 4 }, onClick: () => {
|
|
90
90
|
const mesh = selectedNode.object;
|
|
91
91
|
const geo = mesh.geometry;
|
|
92
92
|
const idx = geo.index;
|